﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace NUnit.Framework
{
    public static class EnumerableAssertions
    {
        public static void ShouldBeEmpty<T>(this IEnumerable<T> actual)
        {
            CollectionAssert.IsEmpty(actual);
        }

        public static IEnumerable<T> ShouldNotBeEmpty<T>(this IEnumerable<T> actual)
        {
            CollectionAssert.IsNotEmpty(actual);
            return actual;
        }

        public static void ShouldContain<T>(this IEnumerable<T> actual, T expected)
        {
            if (actual.Count(t => t.Equals(expected)) == 0)
            {
                Assert.Fail(string.Format("{0} was not found in {1}.", expected, actual));
            }
        }

        public static IEnumerable<T> ShouldContain<T>(this IEnumerable<T> actual, Func<T, bool> expected)
        {
            actual.ShouldNotBeEmpty();
            actual.FirstOrDefault(expected).ShouldNotEqual(default(T), "Exepected item was not found.");
            return actual;
        }

        public static IEnumerable<T> ShouldNotContain<T>(this IEnumerable<T> actual, Func<T, bool> expected)
        {
            actual.Where(expected).ShouldBeEmpty();
            return actual;
        }

        public static IEnumerable<T> ShouldHaveCount<T>(this IEnumerable<T> actual, int expected)
        {
            actual.Count().ShouldEqual(expected);
            return actual;
        }

        public static void ShouldAllEqual<T>(this IEnumerable<T> actual, Func<T, object> func, object expected)
        {
            foreach (var i in actual) func(i).ShouldEqual(expected);
        }

        public static void ShouldAllBeTrue<T>(this IEnumerable<T> actual, Func<T, bool> expected)
        {
            foreach (var a in actual) expected(a).ShouldBeTrue();
        }

        public static void ShouldAllBeFalse<T>(this IEnumerable<T> actual, Func<T, bool> expected)
        {
            foreach (var a in actual) expected(a).ShouldBeFalse();
        }

        public static void ShouldBeSortedAscending<T, TProperty>(this IEnumerable<T> enumerable, Func<T, TProperty> property) where TProperty : IComparable
        {
            var first = false;
            var previousValue = default(TProperty);

            foreach (var value in enumerable)
            {
                if (!first)
                {
                    previousValue = property(value);
                    first = true;
                    continue;
                }

                if (previousValue != null)
                {
                    if (property(value) == null) Assert.Fail();
                    Assert.GreaterOrEqual(property(value), previousValue);
                }

                previousValue = property(value);
            }
        }

        public static void ShouldBeSortedDescending<T, TProperty>(this IEnumerable<T> enumerable, Func<T, TProperty> property) where TProperty : IComparable
        {
            var first = false;
            var previousValue = default(TProperty);

            foreach (var value in enumerable)
            {
                if (!first)
                {
                    previousValue = property(value);
                    first = true;
                    continue;
                }

                if (property(value) != null)
                {
                    if (previousValue == null) Assert.Fail();
                    Assert.LessOrEqual(property(value), previousValue);
                }

                previousValue = property(value);
            }
        }
    }
}